//
//  com.oos.kraken
//
//  Created by Pablo Gonzalez on 2/15/11.
//

#ifdef OOS_TESTING

#import "OosServicesTests.h"
#import "../Atom/Entries/OosServiceEntry.h"
#import "../Atom/Queries/OosSearchQuery.h"
#import "../Parsers/OosServiceFeedParser.h"
@implementation OosServicesTests


- (void) setUp
{
	NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
	[notificationCenter addObserver:self 
						   selector:@selector(fetchStateChanged:) 
							   name:kGDataHTTPFetcherStartedNotification object:nil];
	[notificationCenter addObserver:self 
						   selector:@selector(fetchStateChanged:) 
							   name:kGDataHTTPFetcherStoppedNotification object:nil];
	[notificationCenter addObserver:self 
						   selector:@selector(parseStateChanged:) 
							   name:kGDataServiceTicketParsingStartedNotification object:nil];
	[notificationCenter addObserver:self 
						   selector:@selector(parseStateChanged:) 
							   name:kGDataServiceTicketParsingStoppedNotification object:nil];
	[notificationCenter addObserver:self 
						   selector:@selector(retryDelayStateChanged:) 
							   name:kGDataHTTPFetcherRetryDelayStartedNotification object:nil];
	[notificationCenter addObserver:self 
						   selector:@selector(retryDelayStateChanged:) 
							   name:kGDataHTTPFetcherRetryDelayStoppedNotification object:nil];
}

- (void)fetchStateChanged:(NSNotification *)note {
	GDataHTTPFetcher *fetcher = [note object];
	GDataServiceTicketBase *ticket = [fetcher ticket];
	
	STAssertNotNil(ticket, @"cannot get ticket from fetch notification");
	
	if ([[note name] isEqual:kGDataHTTPFetcherStartedNotification]) {
		fetchStartedCount++;
	} else {
		fetchStoppedCount++;
	}
	
	STAssertTrue(delayStartedCount <= fetchStartedCount,
				 @"fetch notification imbalance: starts=%d stops=%d",
				 fetchStartedCount, delayStartedCount);
}

- (void)parseStateChanged:(NSNotification *)note {
	GDataServiceTicketBase *ticket = [note object];
	
	STAssertTrue([ticket isKindOfClass:[GDataServiceTicketBase class]],
				 @"cannot get ticket from parse notification");
	
	if ([[note name] isEqual:kGDataServiceTicketParsingStartedNotification]) {
		parseStartedCount++;
	} else {
		parseStoppedCount++;
	}
	
	STAssertTrue(parseStoppedCount <= parseStartedCount,
				 @"parse notification imbalance: starts=%d stops=%d",
				 parseStartedCount, parseStoppedCount);
}

- (void)retryDelayStateChanged:(NSNotification *)note {
	GDataHTTPFetcher *fetcher = [note object];
	GDataServiceTicketBase *ticket = [fetcher ticket];
	
	STAssertNotNil(ticket, @"cannot get ticket from retry delay notification");
	
	if ([[note name] isEqual:kGDataHTTPFetcherRetryDelayStartedNotification]) {
		delayStartedCount++;
	} else {
		delayStoppedCount++;
	}
	
	STAssertTrue(delayStoppedCount <= delayStartedCount,
				 @"retry delay notification imbalance: starts=%d stops=%d",
				 delayStartedCount, delayStoppedCount);
}

- (void)resetFetchResponse {
	[mFeed release];
	mFeed = nil;
	
	[mError release];
	mError = nil;
	
	retryCounter = 0;
	
	lastProgressDeliveredCount = 0;
	lastProgressTotalCount = 0;
	
	// Set the UA to avoid log warnings during tests, except the first test,
	// which will use an auto-generated user agent
	if ([service userAgent] == nil) {
		[service setUserAgent:@"oos-UnitTests"];
	}
	
	if (![service shouldCacheDatedData]) {
		// we don't want to see 304s in our service response tests now,
		// though the tests below will check for them in the underlying
		// fetchers when we get a cached response
		[service clearLastModifiedDates];
	}
	
	fetchStartedCount = 0;
	fetchStoppedCount = 0;
	parseStartedCount = 0;
	parseStoppedCount = 0;
	delayStartedCount = 0;
	delayStoppedCount = 0;
}

- (void)tearDown {
	
	[service release];
	service = nil;
	
	[self resetFetchResponse];
}

// deleteResource calls don't return data or an error, so we'll use
// a global int for the callbacks to increment to say they're done
// (because NSURLConnection is performing the fetches, all this
// will be safely executed on the same thread)
static int gFetchCounter = 0;

- (void)waitForFetch {
	
	int fetchCounter = gFetchCounter;
	
	// Give time for the fetch to happen, but give up if
	// 10 seconds elapse with no response
	NSDate* giveUpDate = [NSDate dateWithTimeIntervalSinceNow:10.0];
	
	while ((!mFeed && !mError && !mCategoryGroup)
		   && fetchCounter == gFetchCounter
		   && [giveUpDate timeIntervalSinceNow] > 0) {
		
		NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:0.001];
		[[NSRunLoop currentRunLoop] runUntilDate:stopDate];
	}
	
}

#pragma mark Site service Test

- (void) testSiteService {
	OosAtomService *siteService = [[OosAtomService alloc] init];
	siteService.feedClass = [OosServiceFeed class];
	NSURL *testUrl = [NSURL URLWithString:@"place-details.xml" 
							relativeToURL:[[NSBundle bundleForClass:[self class]] bundleURL]];
	siteService.testURL = testUrl;
	[self assertNotNil:siteService withName:@"placeService"];
	service = [siteService retain];
	
	[siteService read: self];
	[self waitForFetch];
	
	[self assertNil:mError withName:@"Error"];
	[self assertNotNil:mFeed withName:@"Entry"];
	
	OosServiceEntry * entry = [((OosServiceFeed *) mFeed) firstEntry]; 
	[self testEntry: entry];
	[self testEntryLocation: entry];
}

- (void) testEntry: (OosServiceEntry *) entry
{
	[self assertNotNil:entry withName: @"entry"];

	[self assertNotNil:[[entry url] stringValue]						
			  withName:@"url"];
	[self assertNotNil:[[entry telephone] stringValue]				
			  withName:@"telephone"];
	[self assertNotNil:[[entry oosId] stringValue]						
			  withName:@"id"];
	[self assertNotNil:[[entry slug] stringValue]						
			  withName:@"slug"];
	[self assertNotNil:[[entry reviewsCounter] stringValue]			
			  withName:@"reviewsCounter"];
	[self assertNotNil:[[entry savedCounter] stringValue]				
			  withName:@"savedCounter"];
	[self assertNotNil:[entry links]						
			  withName:@"links"];
}

- (void) testEntryLocation: (OosServiceEntry *) entry
{
	[self assertNotNil:entry withName: @"entry"];
	
	[self assertNotNil:[[entry address] stringValue]					
			  withName:@"address"];
	[self assertNotNil:[[entry subDependentLocality] stringValue]		
			  withName:@"subDependentLocality"];
	[self assertNotNil:[[entry dependentLocality] stringValue]		
			  withName:@"dependentLocality"];
	[self assertNotNil:[[entry locality] stringValue]					
			  withName:@"locality"];
	[self assertNotNil:[[entry subAdministrativeArea] stringValue]	
			  withName:@"subAdministrativeArea"];
	[self assertNotNil:[[entry administrativeArea] stringValue]		
			  withName:@"administrativeArea"];
	[self assertNotNil:[[entry country] stringValue]					
			  withName:@"country"];
	[self assertNotNil:[entry where]					
			  withName:@"where"];
}

#pragma mark Search Tests

- (void) testSimpleSearch
{
	OosAtomService *searchService = [[OosAtomService alloc] init];
	searchService.feedClass = [OosServiceFeed class];
	NSURL *testUrl = [NSURL URLWithString:@"search.xml" 
							relativeToURL:[[NSBundle bundleForClass:[self class]] bundleURL]];
	searchService.testURL = testUrl;
	NSLog(@"testUrl = %@", testUrl);
	OosSearchQuery *query = [OosSearchQuery query];
	[query setSearchQuery:@"tapas"]; 
	searchService.query = query;
	[searchService read:self];
	[self waitForFetch];
	
	[self assertNil:mError withName:@"Error (testSimpleSearch)"];
	[self assertNotNil:mFeed withName:@"Entry (testSimpleSearch)"];
	
	int counter = 0;
	
	for (OosServiceEntry* entry in [mFeed entries]) {
		if (entry) {
			[self testEntry: entry];
			counter++;
		}
	}
	STAssertTrue(counter == 10, @"There should be 10 elements in the feed");
	[searchService release];
}

- (void) receivedFeed:(OosFeed *)feed
{
	mFeed = feed;
	gFetchCounter++;
}

- (void) problemWithFetch:(NSError *)error
{
	mError = error;
	gFetchCounter++;
}
- (void)receivedCategoryGroup:(id)categotyGroup
{
    mCategoryGroup = categotyGroup;
	gFetchCounter++;
}

- (void)receivedEntry:(OosEntry *)entry
{
	gFetchCounter++;
}

- (id<IOosFeedParser>) feedParser
{
	return [OosServiceFeedParser instance];
}

@dynamic entryParser;
@dynamic categoryParser;
@dynamic feedParser;

@end

#endif
